package com.party.common.utils;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.party.common.kcsm.StudentInfo;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.Security;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: zhaoyongke
 * @create: 2024-05-30 08:54
 * @description: 微信
 */
public class WxUtils {
    private static final Logger log = LoggerFactory.getLogger(WxUtils.class);

    private static String wx_appId = "wx0fa07a6c70897e68"; //小程序id
    private static String wx_secretKey = "625080e0d87e75343781460af32c3fe7"; //小程序密钥
    private static String wx_corpId = "wwcd783e161afd66dd"; //企业id
    private static String wx_agent_corpsecret = "Q6fIwAb57xAPoRJjqWyrOLJg7AqmOiLzxZf-d3sDCnw"; //企业密钥
    private static String wx_agentid = "1000003";
    private static String wx_tokenUrl = "wwcd783e161afd66dd";
    private static final String KEY_ALGORITHM = "AES";
    private static final String ALGORITHM_STR = "AES/CBC/PKCS7Padding";
    private static Key key;
    private static Cipher cipher;

    private static void init(byte[] keyBytes) {
        // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
        int base = 16;
        if (keyBytes.length % base != 0) {
            int groups = keyBytes.length / base + 1;
            byte[] temp = new byte[groups * base];
            Arrays.fill(temp, (byte) 0);
            System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
            keyBytes = temp;
        }
        // 初始化
        Security.addProvider(new BouncyCastleProvider());
        // 转化成JAVA的密钥格式
        key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
        try {
            // 初始化cipher
            cipher = Cipher.getInstance(ALGORITHM_STR, "BC");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 微信小程序 拿code 换取openid
    public static Map<String, String> getWxOpenId(String code) throws Exception {
        HashMap<String, String> map = new HashMap<>();
        // 请求微信服务器，获取用户 oppenid

        // 微信url
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + wx_appId + "&secret=" + wx_secretKey + "&js_code=" + code + "&grant_type=authorization_code";
        //客户端
        OkHttpClient client = new OkHttpClient();
        //用url发起请求
        Request request = new Request.Builder().url(url).build();
        //拿到响应
        Response response = client.newCall(request).execute();
        //如果响应成功，打印返回值
        if (response.isSuccessful()) {
            String body = response.body().string();
            JSONObject jsonObjectResult = JSON.parseObject(body);
            Object openid = jsonObjectResult.get("openid");
            Object sessionKey = jsonObjectResult.get("session_key");
            Object unionid = jsonObjectResult.get("unionid");
            System.out.println("openId:::" + openid + "session_key:" + sessionKey + "unionId:" + unionid);
            System.out.println("微信code：：：：" + code + "微信openid：" + body + "微信url：" + url);
            map.put("openId", openid.toString());
            map.put("sessionKey", sessionKey.toString());
            map.put("unionId", "");
            return map;
        }
        return map;
    }

    public static void main(String[] args) {
//        String accessToken = getAccessToken();
//        System.out.println(accessToken);
//        StudentInfo studentInfo = StudentInfo.builder()
//                .name("张三")
//                .phone("13244366674")
//                .surplusLearnTime("15")
//                .coachName("李老师")
//                .recName("洪亮")
//                .recPhone("13244556768")
//                .upClassTime("2024-05-30 09:00")
//                .className("钢琴")
//                .wxUserId("LiQingRui")
//                .build();
//        boolean sent = sendTextMessage("1", studentInfo);
//        System.out.println(sent);

        String time = "2025-07-11 09:30";
        LocalDateTime targetTime = LocalDateTime.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
        LocalDateTime newTime = targetTime.minusHours(2);
        String newTimeStr = newTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
        System.out.println("减去2小时后的时间是: " + newTimeStr);

        LocalDateTime dateTime = LocalDateTime.parse(newTimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
        int year = dateTime.getYear();
        int month = dateTime.getMonthValue();
        int day = dateTime.getDayOfMonth();
        int hour = dateTime.getHour();
        int minute = dateTime.getMinute();

        System.out.println("年: " + year);
        System.out.println("月: " + month);
        System.out.println("日: " + day);
        System.out.println("时: " + hour);
        System.out.println("分: " + minute);

        // 生成cron表达式
        String cronExpression = String.format("0 %d %d %d %d ? %d",
                    minute, hour, day, month, year);
        System.out.println("生成的cron表达式: " + cronExpression);

        // 计算time距离当前时间还有几个小时
//        LocalDateTime currentTime = LocalDateTime.now();
//        long hoursUntil = ChronoUnit.HOURS.between(currentTime, targetTime);
//        System.out.println("距离目标时间还有: " + hoursUntil + " 小时");
    }

    /**
     * 获取微信token-用于消息通知应用发送消息
     *
     * @return
     */
    public static String getAccessToken() {
//        Object cacheObject_token = redisService.getCacheObject("WX_TOKEN");
//        if(cacheObject_token!=null){
//            log.info("开始获取token=======================从缓存中获取token======================:"+cacheObject_token);
//            return String.valueOf(cacheObject_token);
//        }
        String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + wx_corpId + "&corpsecret=" + wx_agent_corpsecret;
        String res = HttpUtil.get(url);
        JSONObject object = JSONObject.parseObject(res);
        if (!object.get("errcode").toString().equals("0")) {
            throw new RuntimeException("获取微信token失败");
        }
        Object access_token = object.get("access_token");
//        redisService.setCacheObject("WX_TOKEN", access_token, Long.valueOf(expires_in), TimeUnit.SECONDS);
        return access_token.toString();
    }

    /**
     * 发送企业微信消息
     *
     * @param type    消息类型: 0课时到期提醒  1上课前通知
     * @param student 学员信息
     * @return
     */
    public static boolean sendTextMessage(String type, Object student) {
        if (ObjectUtil.isEmpty(student)) {
            throw new RuntimeException("学员信息不能为空");
        }
        StudentInfo studentInfo = JSONObject.parseObject(JSONObject.toJSONString(student), StudentInfo.class);
        checkParam(studentInfo);
        // 获取 AccessToken
        String accessToken = getAccessToken();
        String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken;

        // 构造请求体
        JSONObject message = new JSONObject();
        message.put("touser", studentInfo.getWxUserId());
        message.put("msgtype", "text");
        message.put("agentid", wx_agentid);
        JSONObject text = new JSONObject();
        if ("0".equals(type)) {
            StringBuilder contentBuilder = new StringBuilder();
            contentBuilder.append("【").append(studentInfo.getName()).append("学员课时到期提醒】\n学员名称:").append(studentInfo.getName())
                    .append("\n学员电话:").append(studentInfo.getPhone())
                    .append("\n课程名称:").append(studentInfo.getClassName())
                    .append("\n剩余课时:").append(studentInfo.getSurplusLearnTime())
                    .append("\n教练名称:").append(studentInfo.getCoachName());

            // 只有当推荐人姓名和电话都有值时才添加
            if (StrUtil.isNotEmpty(studentInfo.getRecName()) && StrUtil.isNotEmpty(studentInfo.getRecPhone())) {
                contentBuilder.append("\n推荐人:").append(studentInfo.getRecName())
                        .append("\n推荐人电话:").append(studentInfo.getRecPhone());
            }

            text.put("content", contentBuilder.toString());
        } else {
            text.put("content", "【" + studentInfo.getName() + "学员上课提醒】\n学员名称:" + studentInfo.getName() +
                    "\n上课时间:" + studentInfo.getUpClassTime() +
                    "\n课程名称:" + studentInfo.getClassName());
        }
        message.put("text", text);

        try {
            RestTemplate restTemplate = new RestTemplate();
            // 移除默认的StringHttpMessageConverter（这里防止中文乱码）
            restTemplate.getMessageConverters().removeIf(converter ->
                    converter instanceof StringHttpMessageConverter);
            // 添加支持UTF-8的StringHttpMessageConverter
            StringHttpMessageConverter converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
            converter.setWriteAcceptCharset(false); // 重要！关闭默认字符集
            restTemplate.getMessageConverters().add(0, converter);

            // 设置请求头，确保 Content-Type 是 UTF-8
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.setAcceptCharset(Collections.singletonList(StandardCharsets.UTF_8));
            HttpEntity<String> request = new HttpEntity<>(message.toJSONString(), headers);
            String response = restTemplate.postForObject(url, request, String.class);
            log.error("发送企业微信消息返回数据：{}", response);
            // 解析返回结果
            JSONObject jsonResponse = JSONObject.parseObject(response);
            int errcode = jsonResponse.getIntValue("errcode");
            if (errcode == 0) {
                return true;
            } else {
                log.error("发送企业微信消息失败，错误码：{}，错误信息：{}", errcode, jsonResponse.getString("errmsg"));
                return false;
            }
        } catch (Exception e) {
            log.error("发送企业微信消息请求失败", e);
            return false;
        }
    }

    /**
     * 校验学员信息
     *
     * @param student
     */
    public static void checkParam(StudentInfo student) {
        //  20250808 zhaoyongke
        if (StrUtil.isEmpty(student.getWxUserId())) {
            throw new RuntimeException("消息接收成员微信账号不能为空");
        }
        if (StrUtil.isEmpty(student.getName())) {
            throw new RuntimeException("学员姓名不能为空");
        }
        if (StrUtil.isEmpty(student.getPhone())) {
            throw new RuntimeException("学员电话不能为空");
        }
        if (StrUtil.isEmpty(student.getClassName())) {
            throw new RuntimeException("课程名称不能为空");
        }
        if (StrUtil.isEmpty(student.getCoachName())) {
            throw new RuntimeException("教练名称不能为空");
        }
        //  zhaoyongke 0808 修改
//        if (StrUtil.isEmpty(student.getRecName())) {
//            throw new RuntimeException("推荐人姓名不能为空");
//        }
//        if (StrUtil.isEmpty(student.getRecPhone())) {
//            throw new RuntimeException("推荐人电话不能为空");
//        }
        if (StrUtil.isEmpty(student.getSurplusLearnTime())) {
            throw new RuntimeException("剩余课时不能为空");
        }
        if (StrUtil.isEmpty(student.getUpClassTime())) {
            throw new RuntimeException("上课时间不能为空");
        }
    }


    public static String getMiniProgramCode(String accessToken, String userId, String ercodeImage) throws Exception {
        String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken;
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        connection.setRequestMethod("POST");
        connection.setDoOutput(true);
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()));

        // 构建请求JSON数据
        JSONObject requestData = new JSONObject();
        requestData.put("scene", "userId=" + userId);
        requestData.put("page", "pages/index/business_card/business_card");
        requestData.put("check_path", false);
        requestData.put("env_version", "trial");
//        requestData.put("env_version", "release");
        writer.write(requestData.toString());
        writer.flush();
        writer.close();
        InputStream inputStream = connection.getInputStream();

        BufferedImage bufferedImage = ImageIO.read(inputStream);
        ImageIO.write(bufferedImage, "jpg", new File(ercodeImage));
        String encode = Base64.encode(inputStream);
        inputStream.close();
        return encode;
    }


    public static String getPhoneNumber(String phoneCode) throws Exception {
        //先根据appId和appSecret获取accessToken
        String tokenUrl = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", wx_appId, wx_secretKey);
        String accessToken = String.valueOf(JSON.parseObject(HttpUtil.get(tokenUrl)).get("access_token"));
        //通过token和code来获取用户手机号
        String url = String.format("https://api.weixin.qq.com/wxa/business/getuserphonenumber?code=%s&access_token=%s", phoneCode, accessToken);
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("code", phoneCode);

        HttpHeaders headers = new HttpHeaders();
        HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(paramMap, headers);
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<Object> response = restTemplate.postForEntity(url, httpEntity, Object.class);
        Object body = response.getBody();
        // 解析JSON字符串s
        cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(body);
        cn.hutool.json.JSONObject phoneInfo = jsonObject.getJSONObject("phone_info");
        String phoneNumber = phoneInfo.getStr("phoneNumber");
        System.out.println("微信小程序获取手机号: " + phoneNumber);
        if (StringUtils.isNotEmpty(phoneNumber)) {
            return phoneNumber;
        }
        return "";
    }

    public static String decryptData(String encryptDataB64, String sessionKeyB64, String ivB64) {

        // 检查输入参数是否为空
        if (StringUtils.isEmpty(encryptDataB64) || StringUtils.isEmpty(sessionKeyB64) || StringUtils.isEmpty(ivB64)) {
            throw new IllegalArgumentException("解密参数不能为空");
        }
        try {
            // 解码Base64字符串
            byte[] encryptData = Base64.decode(encryptDataB64);
            byte[] sessionKey = Base64.decode(sessionKeyB64);
            byte[] iv = Base64.decode(ivB64);

            // 检查解码结果是否为空
            if (encryptData == null || sessionKey == null || iv == null) {
                throw new RuntimeException("Base64解码失败，结果为空");
            }

            // 执行解密操作
            byte[] decryptedData = decryptOfDiyIv(encryptData, sessionKey, iv);

            // 检查解密结果是否为空
            if (decryptedData == null) {
                throw new RuntimeException("数据解密失败，结果为空");
            }

            return new String(decryptedData);
        } catch (Exception e) {
            // 捕获所有异常并重新抛出，带上详细信息
            throw new RuntimeException("解密数据失败: " + e.getMessage(), e);
        }

//        return new String(
//                decryptOfDiyIv(
//                        Base64.decode(encryptDataB64),
//                        Base64.decode(sessionKeyB64),
//                        Base64.decode(ivB64)
//                )
//        );
    }

    /**
     * 解密方法
     *
     * @param encryptedData 要解密的字符串
     * @param keyBytes      解密密钥
     * @param ivs           自定义对称解密算法初始向量 iv
     * @return 解密后的字节数组
     */
    private static byte[] decryptOfDiyIv(byte[] encryptedData, byte[] keyBytes, byte[] ivs) {
        byte[] encryptedText = null;
        init(keyBytes);
        try {
            cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivs));
            encryptedText = cipher.doFinal(encryptedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encryptedText;
    }

}
